package hypeerweb;

import java.io.Serializable;


public abstract class SendVisitor implements Visitor
{
   
    public SendVisitor()
    {
        /*
         * The default constructor.
    
    Pre-condition:
        None
    Post-condition:
        True 
         */
    }
    public Parameters createInitialParameters(int target)
    {
        Parameters parameter = new Parameters();
        WebId webId = new WebId(target);
        parameter.set(TARGET_KEY, webId);
        return parameter;
        /*
         * 
         * 
            The SendVisitor visitor expects the parameters to contain a target. This method initializes the parameters with the key-pair (TARGET_KEY, target). If more parameters are required in a subclass this method is overridden. Normally this method is only called by the source node before sending the "message".
            
            Parameters:
                target - the webId of the node we are to perform the target operation on.
            Pre-condition:
                ∃ n (n ∈ HyPeerWeb AND n.webId = target)
            Post-condition:
                (TARGET_KEY, target) ∈ result AND |result| = 1


         */
    }
    //additional methods needed 
    //in Node: are you the target Node and what Node is a step closer to the target Node
    protected void intermediateOperation(Node node, Parameters parameters)
    {
        assert(node != Node.NULL_NODE);
        assert(parameters != null);
        /*
        The intermediate operation to be performed on a node as we traverse to the target node. Often this method does nothing.

        Parameters:
            node - the intermediate node.
            parameters - the parameters to be used when executing the intermediate operation.
        Pre-condition:
            node ≠ null AND parameters ≠ null;
        Post-condition:
            TRUE

            */
    }
    protected abstract void targetOperation(Node node, Parameters parameters);
    
    public void visit(Node node, Parameters parameters)
    {   
        assert(node != Node.NULL_NODE);
        assert(parameters != null);
        
        WebId target = (WebId) parameters.get(TARGET_KEY);
        
        if(node.getWebId().getValue() == target.getValue())
        {
            targetOperation(node,parameters);
        }
        else
        {    
            Node next_step =  node.sendMessageTo(target);
            intermediateOperation(node,parameters);
            next_step.accept(this, parameters);
        }
/*
        If the webId of the node = the target in the parameters then the targetOperation method is performed on the node. Otherwise the itermediateOperation mtheod is performed on the node (this method often does nothing), a node closer to the target node is found, and the accept method is executed on that node passing in this SendVisitor and the parameters.

        Specified by:
            visit in interface Visitor

        Parameters:
            node - the node being visited in the visitor pattern.
            parameters - the parameters being passed along to the node then to the SendVisitor.
        Pre-condition:
            node ≠ null AND parameters ≠ null AND
            ∃ target (target ∈ HyPeerWeb AND (TARGET_KEY, node.webId) ∈ parameters)
        Post-condition:
            node.webId = parameters.get(TARGET_KEY) ⇒ targetOperation(node, parameters).post-condition
            ELSE
                    itermediateOperation(node, parameters).post-condition AND
                    &exist closerNode (
                            closerNode ∈ node.connections AND
                            distanceBetween(closerNode.webId, parameters.get(TARGET_KEY)) < distanceBetween(node.webId, parameters.get(TARGET_KEY)) AND
                            NOT ∃ otherNode(
                                    otherNode ∈ node.connections AND
                                    distance(otherNode.webId, parameters.get(TARGET_KEY) < distance(closerNode.webId, parameters.get(TARGET_KEY)) AND
                            closerNode.accept(this, parameters).post-condition)

*/
    }
    
    protected static final String TARGET_KEY = "target";
}
